package main

import (
	"bufio"
	"context"
	"fmt"
	"os"
	"path/filepath"
	"time"

	"github.com/spf13/viper"

	"rsync-code/common"
	"rsync-code/internal"
	"sync"

	"golang.org/x/sync/errgroup"
	"golang.org/x/sync/semaphore"
)

func init() {
	// 初始化 Log
	common.InitLogger()
	common.InitConfig()
}

func main() {
	// 先执行一次
	if err := runOnce(); err != nil {
		common.Log.Errorf("首次执行出错: %v", err)
	}

	// 每小时执行一次
	ticker := time.NewTicker(time.Hour)
	defer ticker.Stop()
	for range ticker.C {
		common.Log.Info("开始每小时定时执行")
		if err := runOnce(); err != nil {
			common.Log.Errorf("定时执行出错: %v", err)
		}
	}
}

func runOnce() error {
	// 定义文件路径
	filePath := viper.GetString("file_path")

	// 验证文件路径
	if !filepath.IsAbs(filePath) {
		var err error
		filePath, err = filepath.Abs(filePath)
		if err != nil {
			return fmt.Errorf("获取绝对路径失败: %v", err)
		}
	}

	// 尝试打开文件，最多重试3次
	maxRetries := 3
	file, err := openFileWithRetry(filePath, maxRetries)
	if err != nil {
		return fmt.Errorf("打开文件出错: %v", err)
	}
	defer file.Close()

	// 处理文件内容
	if err := processFileContent(file); err != nil {
		return fmt.Errorf("处理文件内容出错: %v", err)
	}

	common.Log.Info("所有项目推送完成")
	return nil
}

func openFileWithRetry(filePath string, maxRetries int) (*os.File, error) {
	backoff := time.Second
	for i := 0; i < maxRetries; i++ {
		file, err := os.Open(filePath)
		if err == nil {
			return file, nil
		}
		common.Log.Errorf("打开文件出错: %v, 重试中...", err)
		time.Sleep(backoff)
		backoff *= 2 // 指数退避
		if i == maxRetries-1 {
			return nil, fmt.Errorf("多次尝试打开文件失败: %v", err)
		}
	}
	return nil, fmt.Errorf("无法打开文件")
}

func processFileContent(file *os.File) error {
	// 创建一个扫描器来读取文件
	scanner := bufio.NewScanner(file)

	// 使用 WaitGroup 管理并发任务
	var wg sync.WaitGroup
	_, ctx := errgroup.WithContext(context.Background())

	// 控制最大并发数
	maxConcurrent := viper.GetInt("max_concurrent")
	if maxConcurrent <= 0 {
		maxConcurrent = 1 // 默认值
	}
	sem := semaphore.NewWeighted(int64(maxConcurrent))

	// 逐行读取文件内容并并发处理
	for scanner.Scan() {
		line := scanner.Text()
		wg.Add(1)
		go func(repoFullName string) {
			defer wg.Done()
			if err := sem.Acquire(ctx, 1); err != nil {
				common.Log.Errorf("获取信号量失败: %v", err)
				return
			}
			defer sem.Release(1)

			if viper.GetBool("enable_create_repo") {
				// 创建仓库
				if !internal.CreateRepo(repoFullName) {
					common.Log.Errorf("创建仓库失败: %s", repoFullName)
				}
			}
			// 配置仓库
			if !internal.SetPushConfig(repoFullName) {
				common.Log.Errorf("配置仓库失败: %s", repoFullName)
			}
			// 同步项目
			if err := internal.GitPushSSH(repoFullName); err != nil {
				common.Log.Errorf("同步项目失败: %s", repoFullName)
			}
		}(line)
	}

	// 等待所有任务完成
	wg.Wait()

	// 检查扫描过程中是否有错误
	if err := scanner.Err(); err != nil {
		return fmt.Errorf("读取文件出错: %v", err)
	}

	return nil
}
